/*
 ============================================================================
 Name        : pml_test.c
 Author      : 
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "pml_bom.h"
#include "pml_shift_and.h"
#include "pml_hg.h"
#include "pml_bg.h"
#include "pml_qgram_grade.h"
#include <sys/time.h>
#include <time.h>

double diff_time(struct timeval *s, struct timeval *e)
{
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */

	if(e->tv_usec < s->tv_usec)
	{
		e->tv_sec -= 1;
		e->tv_usec += 1*1000*1000;
	}
	tv_usec = e->tv_usec - s->tv_usec;
	tv_sec = e->tv_sec - s->tv_sec;

	double res = tv_sec + ((double)tv_usec)/1000000.0;
	return res;
}

double get_tput(double bytes, double time)
{
	return ((bytes*8/1024/1024)/time);
}


int pml_test_bom(int argc, char **argv)
{
	unsigned char *pattern;
	unsigned char *string;
	srand(0);
	if(argc < 2)
	{
		printf("input error!\n");
		return 1;
	}

	pattern = argv[1];

	int a = atoi(argv[2]);
	unsigned char *buffp = malloc(a + 1);
	int i;
	for(i = 0; i< a ; i++)
	{
		buffp[i] = rand()%256;
	}
	buffp[i] = 0;
	string = buffp;

	int pattern_len = strlen(pattern);
	int string_len = a;

	factor_m *pm = new_oracle_m(pattern);
	struct timeval tv_S,tv_E;
	gettimeofday(&tv_S, NULL);
	i = oracle_match(pm, string, string_len, pattern);
	gettimeofday(&tv_E, NULL);
	printf("[%20s] : %.6f Mbps\n", __func__, get_tput(a, diff_time(&tv_S, &tv_E)));
	free_oracle_m(pm);
	free(buffp);
	return 0;
}

int pml_test_shift_and(int argc, char **argv)
{
	shift_and_st st= {};
	unsigned char *pattern;
	unsigned char *string;

	pattern = argv[1];
	string = argv[2];

	pml_shift_and_pre_proc(&st, pattern, strlen(pattern));

	pml_shift_and_match(&st, string, strlen(string));
	return 0;
}

void instr_run()
{
	unsigned long i = 0;
	char tmp[8];
	struct timeval tv_S,tv_E;
	gettimeofday(&tv_S, NULL);
	while(i < 9999999)
	{
		tmp[0] = 9999999 - i;
		i++;
	}
	gettimeofday(&tv_E, NULL);
	printf("[%20s] : %.6f Mbps[%ld][%.6f s]\n", __func__, get_tput(i, diff_time(&tv_S, &tv_E)), i, diff_time(&tv_S, &tv_E));
}

void cache_run()
{
	unsigned long i = 0;
	struct timeval tv_S,tv_E;
	char tmp[9999999];
	i = 0;
	gettimeofday(&tv_S, NULL);
	while(i < 9999999)
	{
		tmp[i] = 9999999 - i;
		i++;
	}
	gettimeofday(&tv_E, NULL);
	printf("[%20s] : %.6f Mbps[%ld][%.6f s]\n", __func__, get_tput(i, diff_time(&tv_S, &tv_E)), i, diff_time(&tv_S, &tv_E));
}

static char Hex2Char(char *a)
{
	char res[2];
	int i =0;
	for(;i<2;i++)
		switch(a[i])
		{
		case '0':
			res[i] = 0;
			break;
		case '1':
			res[i] = 1;
			break;
		case '2':
			res[i] = 2;
			break;
		case '3':
			res[i] = 3;
			break;
		case '4':
			res[i] = 4;
			break;
		case '5':
			res[i] = 5;
			break;
		case '6':
			res[i] = 6;
			break;
		case '7':
			res[i] = 7;
			break;
		case '8':
			res[i] = 8;
			break;
		case '9':
			res[i] = 9;
			break;
		case 'A':
		case 'a':
			res[i] = 10;
			break;
		case 'B':
		case 'b':
			res[i] = 11;
			break;
		case 'C':
		case 'c':
			res[i] = 12;
			break;
		case 'D':
		case 'd':
			res[i] = 13;
			break;
		case 'E':
		case 'e':
			res[i] = 14;
			break;
		case 'F':
		case 'f':
			res[i] = 15;
			break;
		}

	//printf("[%.*s] -> [%c]\n", 2, a, res[0]<<4 | res[1]);
	return (res[0]<<4 | res[1]);
}

int pml_test_hg(int argc, char **argv)
{
	unsigned char *pattern;
	unsigned char *string;
	srand(0);
	if(argc < 3)
	{
		printf("input error!\n");
		return 1;
	}
	int q_size = atoi(argv[3]);
	pml_hg hg;
	pml_hg_init(&hg, q_size);

	char *pattern_file = argv[1];
	char tmp_buff[1024];
	FILE *fp = fopen(pattern_file, "r");
	while(fgets(tmp_buff, sizeof(tmp_buff), fp))
	{
		int pattern_len = strlen(tmp_buff);
		int i = 0, j = 0;

		//for(; i < pattern_len/2; i++,j=i*2)
		//	tmp_buff[i] = Hex2Char(&tmp_buff[j]);
		//pml_hg_add_pat(&hg, tmp_buff, i);
		pml_hg_add_pat(&hg, tmp_buff, pattern_len);
	}
	fclose(fp);

	fp = fopen(argv[2], "r");
	fseek(fp, 0, SEEK_END);
	int a = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	unsigned char *buffp = malloc(a + 1);
	fread(buffp, a, 1, fp);
	fclose(fp);
	buffp[a] = 0;
	string = buffp;
	int string_len = a;

	struct timeval tv_S,tv_E;
	gettimeofday(&tv_S, NULL);
	pml_hg_match(&hg, string, string_len);
	gettimeofday(&tv_E, NULL);
	printf("[%20s] : %.6f Mbps\n avg_shift:[%.6f] shift_count:[%d] hit_count:[%d]\n", __func__, get_tput(a, diff_time(&tv_S, &tv_E)), hg.avg_shift, hg.shift_count, hg.hit_count);

	free(buffp);
	return 0;
}



int pml_test_bg(int argc, char **argv)
{
	unsigned char *pattern;
	unsigned char *string;
	int add_pat_fail = 0;
	srand(0);
	if(argc < 3)
	{
		printf("input error!\n");
		return 1;
	}
	int q_size = atoi(argv[3]);
	int limit_score = atoi(argv[4]);
	pml_bg bg;
	pml_bg_init(&bg, 8, q_size, 1, limit_score);
	pml_load_db_file("qgram_grade.db");

	char *pattern_file = argv[1];
	char tmp_buff[1024];
	int  pat_cnv2file_num = 10;
	FILE *fp = fopen(pattern_file, "r");
	int ttp = 0;
	while(fgets(tmp_buff, sizeof(tmp_buff) - 1, fp))
	{
		int pattern_len = strlen(tmp_buff);
		int i = 0, j = 0;

		for(; i < pattern_len/2; i++,j=i*2)
			tmp_buff[i] = Hex2Char(&tmp_buff[j]);
		int ret = pml_bg_add_pat(&bg, tmp_buff, i);
		if(ret < 0)
		{
			printf("%d\n", ret);
			add_pat_fail++;
		}
//		else
//		{
//			pat_cnv2file_num --;
//			if((pat_cnv2file_num ) >= 0)
//			{
//				FILE *fp = fopen("./pppp.txt", "ab+");
//				fwrite(tmp_buff, 1, i,fp);
//				fwrite("\n\n\n\n", 1, 4,fp);
//				fclose(fp);
//			}
//		}
		//pml_bg_add_pat(&bg, tmp_buff, pattern_len);
	}
	fclose(fp);

	pml_bg_pre_match(&bg);
	printf("add pat fail count:%d\n", add_pat_fail);

	fp = fopen(argv[2], "r");
	fseek(fp, 0, SEEK_END);
	int a = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	unsigned char *buffp = malloc(a + 1);
	fread(buffp, a, 1, fp);
	fclose(fp);
	buffp[a] = 0;
	string = buffp;
	int string_len = a;


	pml_qgram_pos_print();
	pml_qgram_study(buffp, string_len, q_size);
	struct timeval tv_S,tv_E;
	gettimeofday(&tv_S, NULL);
	pml_bg_match(&bg, string, string_len);
	gettimeofday(&tv_E, NULL);
	printf("[%20s] : %.6f Mbps\n avg_shift:[%.6f] shift_count:[%d] hit_count:[%d] verify_count:[%d]\n", __func__, get_tput(a, diff_time(&tv_S, &tv_E)), bg.avg_shift, bg.shift_count, bg.hit_count, bg.verify_count);
	pml_save_db_file("qgram_grade.db");
	free(buffp);
	return 0;
}


void branch_prediction_test()
{
	const unsigned int count = 10000;
	unsigned int i;
	unsigned int a;

	srand(time(NULL));

	for(a = 10,i = 0;i<count;i++)
	{
		if(a >10)
			a--;
		else
			a++;
	}

	for(a = 0,i = 0;i<count;i++)
	{
		a =rand();
		if(a >10)
			a--;
		else
			a++;
	}

	for(a = 0,i = 0;i<count;i++)
	{
		if(a >10)
			a++;
		else
			a++;
	}

	return;
}


int main(int argc, char **argv)
{
	int ret;
	//pml_test_shift_and(argc, argv);
	//ret = pml_test_bom(argc, argv);
	//instr_run();
	//cache_run();
	//pml_test_hg(argc, argv);
	pml_test_bg(argc, argv);
	//branch_prediction_test();

	return ret;
}
